#include "Protocols/ShowableItem.h"
#include "protocols/Icmp.h"
#include "utilities/ReadablePacket.h"
#include "protocols/ProtocalCode.h"
#include "protocols/ProtocalPool.h"

REGISTER_PROTOCOL(Icmp)

using boost::shared_ptr;

QString IcmpHeader::getSummary() const
{
	HeaderFormat* header = (HeaderFormat*)mData;
	if (header->mType == 0&&header->mCode == 0)
	{
		return QString("Echo Reply");
	}
	else if (header->mType == 3)
	{
		switch (header->mCode)
		{
		case 0:
			return QString("Network Unreachable");
		case 1:
			return QString(" Host Unreachable");
		case 2:
			return QString("Protocol Unreachable");
		case 3:
			return QString("Port Unreachable");
		case 4:
			return QString("Fragmentation needed but no frag. bit set");
		case 5:
			return QString("Source routing failed");
		case 6:
			return QString("Destination network unknown");
		case 7:
			return QString("Destination host unknown");
		case 8:
			return QString("Source host isolated (obsolete)");
		case 9:
			return QString("Destination network administratively prohibited");
		case 10:
			return QString("Destination host administratively  prohibited");
		case 11:
			return QString("Network unreachable for TOS");
		case 12:
			return QString("Host unreachable for TOS");
		case 13:
			return QString("Communication administratively prohibited  by filtering");
		case 14:
			return QString("Host precedence violation");
		case 15:
			return QString("Precedence cutoff in effect");
		default:
			return QString("");
		}	
	}
	else if(header->mType == 4 && header->mCode == 0)
	{
		return QString("Source quench");
	}
	else if (header->mType == 5)
	{
		switch(header->mCode)
		{
		case 0:
			return QString("Redirect for network");
		case 1:
			return QString("Redirect for host");
		case 2:
			return QString("Redirect for TOS and network");
		case 3:
			return QString("Redirect for TOS and host");
		default:
			return QString("");
		}
	}
	else if (header->mType == 8&&header->mCode == 0)
	{
		return QString("Echo request");
	}
	else if (header->mType == 9&&header->mCode == 0)
	{
		return QString("Router advertisement");
	}
	else if (header->mType == 10&&header->mCode == 0)
	{
		return QString("Router solicitation");
	}
	else if (header->mType == 11)
	{
		if (header->mCode == 0)
		{
			return QString("TTL equals 0 during transit");
		}
		else if (header->mCode == 1)
		{
			return QString("TTL equals 0 during reassembly");
		}
		else return QString("");
	}
	else if (header->mType == 12)
	{
		if (header->mCode == 0)
		{
			return QString("IP header bad(carchall error)");
		}
		else if (header->mCode == 1)
		{
			return QString("Required options missing");
		}
		else return QString("");
	}
	else if (header->mType == 13 && header->mCode == 0)
	{
		return QString("Timestamp request(obsolete)");
	}
	else if (header->mType == 14)
	{
		return QString("Timedtamp reply(obsolete)");
	}
	else if (header->mType == 15 && header->mCode == 0)
	{
		return QString("Information request(obsolete)");
	}
	else if (header->mType == 16 && header->mCode == 0)
	{
		return QString("Information reply(obsolete)");
	}
	else if (header->mType == 17 && header->mCode == 0)
	{
		return QString("Address mask request");
	}
	else if (header->mType == 18 && header->mCode == 0)
	{
		return QString("Address mask reply");
	}
	else return QString("");
}

void IcmpHeader::toShowableItems(ShowableItem* root) const{
	HeaderFormat* header = (HeaderFormat*)mData;
	int pos = mPos;
	ShowableItem* tmp;

	ShowableItem* proto = createProtocalItem("Internet Control Message Protocol",pos,getHeaderLength());
	root->pushChild(proto);

	tmp = createItem("Type:",header->mType,pos,1);
	proto->pushChild(tmp);

	tmp = createItem("Code:",header->mCode,pos,1);
	proto->pushChild(tmp);

	tmp = createItem("Header Checksum:",toHexString(pointer(pos),2),pos,2);
	proto->pushChild(tmp);

	tmp = createItem("Identifier:",toHexString(pointer(pos),2),pos,2);
	proto->pushChild(tmp);

	tmp = createItem("Sequence Number:",ntohs(header->mSequenceNumber),pos,2);
	proto->pushChild(tmp);
}

Icmp::Icmp():Protocol(ICMP,QString("ICMP"))
{
}

shared_ptr<PacketHeader> Icmp::analyzeProc(shared_ptr<ReadablePacket> packet,int low,int high,shared_ptr<Protocol>& tip)
{
	shared_ptr<IcmpHeader> header(new IcmpHeader(PROTOCOL_POINTER(Icmp),packet->getData(),low,high - low + 1));
	tip.reset();

	return header;
}